/*!
 @Description 百度地图解析经纬度存在哪个省内
 @Author cz
 */

;!(function (win, $) {
    "use strict";

    var doc = document
        /**
         * 查找当前js的目录
         */
        ,getPath = function () {
            var jsPath = doc.currentScript ? doc.currentScript.src : function () {
                var js = doc.scripts
                    , last = js.length - 1
                    , src;
                for (var i = last; i > 0; i--) {
                    if (js[i].readyState === 'interactive') {
                        src = js[i].src;
                        break;
                    }
                }
                return src || js[last].src;
            }();
            return jsPath.substring(0, jsPath.lastIndexOf('/') + 1);
        }()

        ,isArray = function (obj) {
            return Array.isArray ? Array.isArray(obj) : "[object Array]" === Object.prototype.toString.call(obj);
        }

        ,isString = function (obj) {
            return "[object String]" === Object.prototype.toString.call(obj);
        }

        ,ParseArea = function () {
            this._initial();
        }

        ,Hashtable = function() {
            this._initial();
        }

    ParseArea.prototype = {
        _initial:function () {
            this.v = '1.0.0'; //版本号
            this.isload = false;
            this.provinceData = [];//省份边界经纬度数据
            this.cache = new Hashtable();
            this._initJSON();
        }
        ,_initJSON:function () {
            var _this = this;
            $.getJSON(getPath + '/simple_province.json', function (data) {
                _this.provinceData = data;
                _this.isload = true
            })
        }

        /**
         * 获取省级行政区划边界数据
         * @param zoning 行政区划
         * @returns {[]}
         */
        ,getProvinceData : function(zoning){
            zoning = this.getTopZoning(zoning);
            var polygons = this.provinceData[zoning];

            if (common.checkBMap()){
                if (isString(polygons.latlng)){
                    var pts = [];
                    var array = polygons.latlng.split(';');
                    for (var i = 0,len = array.length; i < len; i++) {
                        var lnglat = array[i].split(',');
                        var pt = new BMap.Point(parseFloat(lnglat[0]),parseFloat(lnglat[1]));
                        pts.push(pt);
                    }
                    polygons.latlng = new BMap.Polygon(pts);
                }
                return polygons;
            }

            if (isArray(polygons.latlng)){
                return polygons;
            }
            if (isString(polygons.latlng)){
                var array = [];
                var lnglat = polygons.latlng.split(';');
                for (var i = 0,len = lnglat.length; i < len; i++) {
                    var data = lnglat[i].split(',');
                    array.push(data);
                }
                polygons.latlng = array;
                return polygons;
            }
        }

        /**
         * 根据子级行政区划获取省级行政区划
         * @param zoning 行政区划
         * @returns {string|null}
         */
        ,getTopZoning : function(zoning){
            if(!zoning){
                return null;
            }
            return zoning.toString().substring(0,2) + "0000";
        }

        /**
         * 根据经纬度解析在哪个省
         * @param lng
         * @param lat
         * @param callback
         */
        ,judgeExistsProvince : function (lng,lat,callback) {
            if (!this.isload){
                var _this = this;
                setTimeout(function () {
                    _this.judgeExistsProvince(lng,lat,callback);
                },100)
                return;
            }
            var lnglat = lng + ',' + lat,
                results = this.cache.get(lnglat);

            if (results){
                results === 'null' ?  callback(null) : callback(results);
                return;
            }
            //TODO 射线法可以先切片过滤一下
            for (var key in this.provinceData) {
                var polygons = this.getProvinceData(key);
                if (common.rayCasting(lng,lat,polygons.latlng)){
                    var result = {name:polygons.province,zoning:polygons.zoning};
                    this.cache.put(lnglat,result);
                    callback(result);
                    return;
                }
            }
            this.cache.put(lnglat,'null');
            callback(null);
        }

        /**
         * 根据省份、经纬度解析是否出省
         * @param lng
         * @param lat
         * @param zoning 行政区划
         * @param callback
         */
        ,judgeNotExistsProvince : function (lng,lat,zoning,callback) {
            if (!this.isload){
                var _this = this;
                setTimeout(function () {
                    _this.judgeNotExistsProvince(lng,lat,zoning,callback);
                },100)
                return;
            }
            var polygons = this.getProvinceData(zoning);
            var result = !common.rayCasting(lng,lat,polygons.latlng);
            callback(result);
        }
    }

    Hashtable.prototype = {
        _initial: function () {
            this.count = 0;
            this.entry = {};
        },
        put: function (key, value) {
            if (!this.containsKey(key)) {
                this.count++;
            }
            this.entry[key] = value;
        },
        get: function (key) {
            return this.containsKey(key) ? this.entry[key] : null;
        },
        remove: function (key) {
            var item = this.entry[key];
            if (this.containsKey(key) && (delete this.entry[key])) {
                this.count--;
            }
            return item;
        },
        removeArr: function (arr) {
            for (var i = 0; i < arr.length; i++) {
                this.remove(arr[i])
            }
        },
        containsKey: function (key) {
            return (key in this.entry);
        },
        containsValue: function (value) {
            for (var prop in this.entry) {
                if (this.entry[prop] == value) {
                    return true;
                }
            }
            return false;
        },
        getValues: function () {
            var values = [];
            for (var prop in this.entry) {
                values.push(this.entry[prop]);
            }
            return values;
        },
        getFirstKey: function () {
            for (var prop in this.entry) {
                return prop;
            }
        },
        getKeys: function () {
            var keys = [];
            for (var prop in this.entry) {
                keys.push(prop);
            }
            return keys;
        },
        size: function () {
            return this.count;
        },
        clear: function () {
            this.count = 0;
            this.entry = {};
        },
        each: function (callback) {
            for (var key in this.entry) {
                var value = this.entry[key];
                callback(key, value);
            }
        }
    }



    var common = {
        hasBMp:null,
        silce:[
            {zoning:'440000',rectangle:[]},
            {zoning:'420000',rectangle:[]},
            {zoning:'610000',rectangle:[]},
            {zoning:'140000',rectangle:[]},
            {zoning:'130000',rectangle:[]},
            {zoning:'110000',rectangle:[]},
            {zoning:'120000',rectangle:[]},
            {zoning:'210000',rectangle:[]},
            {zoning:'220000',rectangle:[]},
            {zoning:'230000',rectangle:[]},
            {zoning:'370000',rectangle:[]},
            {zoning:'320000',rectangle:[]},
            {zoning:'310000',rectangle:[]},
            {zoning:'340000',rectangle:[]},
            {zoning:'360000',rectangle:[]},
            {zoning:'410000',rectangle:[]},
            {zoning:'330000',rectangle:[]},
            {zoning:'350000',rectangle:[]},
            {zoning:'430000',rectangle:[]},
            {zoning:'450000',rectangle:[]},
            {zoning:'520000',rectangle:[]},
            {zoning:'500000',rectangle:[]},
            {zoning:'510000',rectangle:[]},
            {zoning:'530000',rectangle:[]},
            {zoning:'620000',rectangle:[]},
            {zoning:'630000',rectangle:[]},
            {zoning:'640000',rectangle:[]},
            {zoning:'150000',rectangle:[]},
            {zoning:'650000',rectangle:[]},
            {zoning:'540000',rectangle:[]},
            {zoning:'460000',rectangle:[]},
            {zoning:'810000',rectangle:[]},
            {zoning:'820000',rectangle:[]},
            {zoning:'710000',rectangle:[]},
        ],
        checkBMap:function(){
            if (this.hasBMp != null){
                return this.hasBMp;
            }

            this.hasBMp = typeof BMap != 'undefined' && BMap && typeof BMapLib != 'undefined' && BMapLib;
            if (!this.hasBMp) {
                console.log('%c建议引入https://api.map.baidu.com/api?v=3.0&ak=你的秘钥,https://api.map.baidu.com/library/GeoUtils/1.2/src/GeoUtils_min.js', 'color:#fff;background-color:orange;');
            }
            return this.hasBMp;
        },
        /**
         * 根据每个省的矩形切片，先过滤一遍经纬度可能在哪个省
         */
        slicePrivince:function(){

        },
        rayCasting:function (lng,lat,poly) {
            return this.checkBMap() ? baidu.rayCasting(lng,lat,poly) : native.rayCasting(lng,lat,poly);
        }

    },native = {
        /**
         * 根据某点坐标判断该坐标是否在某区域坐标范围内 射线法
         * @param lng 目标经度
         * @param lat 目标纬度
         * @param poly 区域经纬度集合
         * @returns {boolean}
         */
        rayCasting:function (lng,lat,poly) {
            var px = parseFloat(lng),
                py = parseFloat(lat),
                flag = false

            for(var i = 0, l = poly.length, j = l - 1; i < l; j = i, i++) {
                var sx = parseFloat(poly[i][0]),
                    sy = parseFloat(poly[i][1]),
                    tx = parseFloat(poly[j][0]),
                    ty = parseFloat(poly[j][1])

                // 点与多边形顶点重合
                if((sx === px && sy === py) || (tx === px && ty === py)) {
                    return true
                }

                // 判断线段两端点是否在射线两侧
                if((sy < py && ty >= py) || (sy >= py && ty < py)) {
                    // 线段上与射线 Y 坐标相同的点的 X 坐标
                    var x = sx + (py - sy) * (tx - sx) / (ty - sy)

                    // 点在多边形的边上
                    if(x === px) {
                        return true
                    }

                    // 射线穿过多边形的边界
                    if(x > px) {
                        flag = !flag
                    }
                }
            }

            // 射线穿过多边形边界的次数为奇数时点在多边形内
            return flag
        }
    },baidu = {
        /**
         * 根据某点坐标判断该坐标是否在某区域坐标范围内 百度api
         * @param lng 目标经度
         * @param lat 目标纬度
         * @param poly 区域经纬度集合
         * @returns {boolean}
         */
        rayCasting:function (lng,lat,poly) {
            var pt = new BMap.Point(lng, lat);
            return BMapLib.GeoUtils.isPointInPolygon(pt, poly);
        }
    }



    if (typeof module !== "undefined" && module.exports) {
        module.exports = {
            parseArea: new ParseArea(),
        };
    } else if (typeof define === "function" && define.amd) {
        define(function () {
            return {
                parseArea: new ParseArea(),
            };
        });
    } else {
        !('parseArea' in win) && (win.parseArea = new ParseArea());
    }

})(window, jQuery)